package org.chnxi.study.concurrent.countdownlunch.demo1;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class CountDownLunchTest {

    private CountDownLatch countDownLatch = new CountDownLatch(5);

    public void doWork(){
        try{
            TimeUnit.MILLISECONDS.sleep(50); // 模拟业务耗时
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"-执行业务单元");
        countDownLatch.countDown();
        System.out.println(Thread.currentThread().getName()+"-countdown="+countDownLatch.getCount());
    }

    /**
     * 执行结果：
     * 主线程开始工作
     * T-0-执行业务单元
     * T-4-执行业务单元
     * T-4-countdown=3
     * T-2-执行业务单元
     * T-1-执行业务单元
     * T-1-countdown=1
     * T-3-执行业务单元
     * T-2-countdown=2
     * T-0-countdown=4
     * 业务单元全部执行完成，回到主线程
     * T-3-countdown=0
     *
     *  CountDownLatch，意思是倒数门闩。它的作用是多个线程做汇聚，主线程需要等待子线程全部完成后才能继续后面的步骤。
     *  CountDownLatch 的await方法会阻塞主线程，直到计数走到 0，门闩才会打开，主线程继续执行
     *  CountDownLatch 只能使用一次，计数到0后不再发生变化。
     */
    public static void main(String[] args) throws Exception {
        System.out.println(">>>>>主线程开始工作");
        CountDownLunchTest test = new CountDownLunchTest();

        for(int i=0; i<5; i++){
            Thread thread = new Thread(() -> {
                test.doWork();
            }, "T-" + i);//.start();
            thread.setDaemon(true);
            thread.start();
        }

        test.countDownLatch.await(); // 等待子线程执行完成
        System.out.println(">>>>>业务单元全部执行完成，回到主线程");

        //此处代码将会发生不执行的问题，因为共同使用的CountDownLunch已经计数归零
        for(int i=0; i<5; i++){
            Thread thread = new Thread(() -> {
                test.doWork();
            }, "TT-" + i);//.start();
            thread.setDaemon(true);
            thread.start();
        }

        test.countDownLatch.await();
        System.out.println(">>>>>业务单元全部执行完成，将推出主线程");
    }

}
